单个参数的传递
通过#{参数名}
取出参数值,实际上在传递单个参数的时候,MyBatis
不会做特殊处理,实际上#{}
内部的参数名你可以任意取值,但还是建议和接口中参数的名字保持一致。
多个参数的传递
MyBatis
遇见多个参数时会进行特殊处理,多个参数会被封装成一个Map
,#{}
就是从Map
中获取指定key
的值,key
的值为param1...paramN
,而value
才是我们传入的值。要想从传入的Map
中取值,只能通过#{param1}
、#{param2}
…或者#{0}
、#{1}
…
|
|
其对应的SQL
映射为:
|
|
然后进行测试:
|
|
这种方法虽然可以使用,但是不够直观,因此,通常使用命名参数:明确指定封装参数时Map
的key
,不要再使用param1、param2...
,可以使用@Param
注解来完成。
|
|
这样,在封装Map
时所使用的key
就是id和lastName。
另一方面,如果参数很多,正好是业务逻辑的数据模型,我们就可以直接传入POJO
,此时使用#{属性名}
就可以取出传入的POJO
属性值。
如果多个参数不是业务逻辑的数据模型,没有对应的POJO
,为了方便,我们也可以传入Map
,此时#{key}
就是取出Map
中对应的值。
|
|
|
|
|
|
如果多个参数不是业务模型中的数据,但是经常要使用,推荐编写一个TO(Transfer Object)
数据传输对象。比如分页查询的时候封装一个Page
:
|
|
需要注意的是,如果接口参数类型为Collection(List、Set
)类型或者是数组也会特殊处理,也是把传入的List或者数组封装在Map
中,若为Collection
,key
使用的是collection
,若为List
,key
还可以使用list
;若为数组,则key
使用的是array
,例如:
假设接口如下:
|
|
则取值的时候取出第一个id的值需要使用#{list[0]}
。
参数值的获取
#{}
可以获取Map
中的值或者POJO
对象属性的值,对于MyBatis
来说,还支持${}
的取值方式。两者的区别在于:#{}
是以预编译的形式将参数设置到SQL
语句中,可以防止SQL
注入,而${}
取出的值直接拼装在SQL
语句中,会有安全问题。
大多情况下我们取参数的值都应该使用#{}
,对于原生JDBC
不支持占位符的地方就可以使用${}
进行取值。举个例子:
分表操作,按照年份分表拆分:
|
|
原生JDBC是不能如下操作的:
|
|
此时可以使用${}
进行取值。
再比如排序:
|
|
同样地,原生JDBC
不支持order by
后面使用占位符。
参数处理
参数可以指定一个特殊的数据类型:
12#{property, javaType=int, jdbcType=NUMERIC}#{height, javaType=double, jdbcType=NUMERIC, numericScale=2}javaType
通常可以从参数对象中来确定- 如果
null
被当做值来传递,对于所有可能为空的列,jdbcType
需要被设置 - 对于数值类型,还可以设置小数点后保留的位数
mode
属性(存储过程)允许指定IN
、OUT
或INOUT
参数,如果参数为OUT
或INOUT
,参数对象属性的真实值将会被改变
jdbcType
通常需要在某种特定的条件下被设置:在我们数据为null
的时候,有些数据库可能不能识别MyBatis
对null
的默认处理比如Oracle
,Oracle
会报JdbcType OTHER无效的类型
错误。MyBatis
对所有的null映射的是原生Jdbc
的OTHER
类型,Oracle
不能正确处理。此时可以做如下设置:
1#{email, jdbcType=NULL}这是因为全局配置中
jdbcTypeForNull=OTHER
,Oracle
不支持,因此主要有以下两种解决办法:#{email, jdbcType=OTHER}
这种解决方法只会影响当前
SQL
语句的jdbcType
。更改全局配置中
jdbcTypeForNull
,将其改为NULL
即可,如下:123<settings><setting name="jdbcTypeForNull" value="NULL"/></settings>